package com.clementheliou.cheliou.dal.dao.generic.impl;

import java.lang.reflect.ParameterizedType;

import org.hibernate.Query;

import com.clementheliou.cheliou.dal.dao.base.impl.BaseHibernateDAO;
import com.clementheliou.cheliou.dal.dao.generic.GenericDAO;
import com.clementheliou.cheliou.dal.model.base.BaseEntity;

/**
 * Hibernate-based implementation of the {@link GenericDAO} interface for a given {@link BaseEntity}
 * subclass. This last one represents a model entity. {@link BaseHibernateDAO} is extended to access
 * to the current Hibernate session and unparameterized common methods.
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @param <T> the parameterized type. It must extend {@link BaseEntity}.
 * @see {@link BaseHibernateDAO};
 * @see {@link BaseEntity};
 * @see {@link GenericDAO}.
 * @since 1.0
 */
public abstract class GenericHibernateDAO<T extends BaseEntity> extends BaseHibernateDAO implements GenericDAO<T> {

	/**
	 * <i>{@inheritDoc}</i>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T getEntity(Integer id) {
		return (T) getCurrentSession().get(getEntityClass(), id);
	}

	/**
	 * <i>{@inheritDoc}</i>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T loadEntity(Integer id) {
		return (T) getCurrentSession().load(getEntityClass(), id);
	}

	/**
	 * Gets the class of the <code>T</code> entity.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the <code>T</code> entity class.
	 * @since 1.0
	 */
	@SuppressWarnings("unchecked")
	private Class<T> getEntityClass() {
		return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * <i>{@inheritDoc}</i>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Override
	public Integer saveEntity(T entity) {
		return (Integer) getCurrentSession().save(entity);
	}

	/**
	 * <i>{@inheritDoc}</i>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Override
	public void deleteEntity(T entity) {
		getCurrentSession().delete(entity);
	}

	/**
	 * <i>{@inheritDoc}</i>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Override
	@SuppressWarnings("unchecked")
	public T mergeEntity(T entity) {
		return (T) getCurrentSession().merge(entity);
	}

	/**
	 * <i>{@inheritDoc}</i>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Override
	public Integer count() {
		final StringBuilder queryBuilder = new StringBuilder("SELECT COUNT(*) ");
		queryBuilder.append("FROM ").append(getEntityClass().getName());

		final Query query = getCurrentSession().createQuery(queryBuilder.toString());
		return ((Long) query.uniqueResult()).intValue();
	}
}
